﻿namespace GoogleOAuth.Models
{
    using System;
    using System.Net;
    using System.Linq;
    using System.Collections.Generic;
    
    using Microsoft.Phone.Controls;
    
    public class GoogleClient : IGoogleClient
    {
        private WebBrowser _browserControl;
        private string _clientId;
        private string _clientSecret;
        private bool _initialized;
        private string _callback;

        public delegate void AuthenticationCompletedHandler(object sender, GoogleAccount account);

        public event AuthenticationCompletedHandler AuthenticationCompleted;

        protected virtual void OnAuthenticationCompleted(GoogleAccount account)
        {
            AuthenticationCompletedHandler handler = AuthenticationCompleted;
            if (handler != null) handler(this, account);
        }

        public void Initialize(WebBrowser browserControl, string clientId, string clientSecret, string callback)
        {
            _initialized = true;
            _clientSecret = clientSecret;
            _clientId = clientId;
            _browserControl = browserControl;
            _callback = callback;
        }

        public void LoginAsync()
        {
            if (!_initialized)
            {
                throw new Exception("Google client is not initialized");
            }
            _browserControl.Navigating += BrowserNavigating;
            _browserControl.Navigate(
                new Uri(
                    string.Format(
                        "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={0}&scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile&redirect_uri="+ _callback + "&approval_prompt=force",
                        _clientId)));
        }

        async void BrowserNavigating(object sender, NavigatingEventArgs e)
        {
            try
            {
                KeyValuePair<string, string> code;
                if (RetrieveCode(e, out code)) return;

                HttpWebRequest request =
                    WebRequest.CreateHttp("https://accounts.google.com/o/oauth2/token");

                GoogleToken token = await request.GetValueFromRequest<GoogleToken>(string.Format(
                    "code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type={4}",
                    code.Value,
                    _clientId,
                    _clientSecret,
                    _callback,
                    "authorization_code"));

                request = WebRequest.CreateHttp("https://www.googleapis.com/oauth2/v2/userinfo");
                request.Headers["Authorization"] = string.Format("{0} {1}", token.TokenType, token.AccessToken);
                var account = await request.GetValueFromRequest<GoogleAccount>();
                OnAuthenticationCompleted(account);
            }
            catch (Exception)
            {
              OnAuthenticationCompleted(null);
            }
        }

        private static bool RetrieveCode(NavigatingEventArgs e, out KeyValuePair<string, string> code)
        {
            if (string.IsNullOrEmpty(e.Uri.Query))
            {
                return true;
            }
            string query = HttpUtility.UrlDecode(e.Uri.Query);

            var dict = query.TrimStart('?')
                .Split('&')
                .Select(
                    p =>
                        new KeyValuePair<string, string>(p.Split('=').FirstOrDefault(), p.Split('=').LastOrDefault()));

            var keyValuePairs = dict as KeyValuePair<string, string>[] ?? dict.ToArray();

            if (!keyValuePairs.Any(q => q.Key == "code")) return true;

            code = keyValuePairs.FirstOrDefault(k => k.Key == "code");
            return false;
        }
    }

}
